﻿using System;
using System.Collections.Generic;
using System.Linq;

using System.Data.Entity;

using MvcCms.Data;
using MvcCms.Service.Logging;
using MvcCms.Service.Code;
using MvcCms.Data.Service;
using MvcCms.Data.Service.Code;
using MvcCms.Service;
using System.Data.Objects.SqlClient;

namespace MvcCms.Store.Service.Code
{
    /// <summary>
    /// Provides Business Logic Should Be Placed Here Unless Data Specific such as limiting results returned.
    /// Do ToList here.
    /// </summary>
    public class StoreService : IStoreService
    {
        #region Constructors
        private readonly IStoreRepository _repository;
        private readonly IAccountDataService _accountDataService;
        private readonly IAccountService _accountService;
        public StoreService(IAccountService accountService, IAccountDataService accountDataService, IStoreRepository repository)
        {
            _repository = repository;
            _accountDataService = accountDataService;
            _accountService = accountService;
        }
        #endregion

        public User GetUserIncCC()
        {
            return _accountService.GetUser();
        }

        public bool CreatePriceOption(StorePricingOption priceOptionToCreate)
        {
            try
            {
                _repository.CreatePriceOption(priceOptionToCreate);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }

        public bool CreateProduct(StoreProduct productToCreate)
        {
            try
            {
                _repository.CreateProduct(productToCreate);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }

        public bool CreateOrder(StoreOrder orderToCreate)
        {
            try
            {
                _repository.CreateOrder(orderToCreate);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }

        public IEnumerable<StoreCart> GetCartWithProduct(string shoppingCartID)
        {
            var query = _repository.ListStoreCartItems().AsQueryable();

            query = query.Where(p => p.CartID == shoppingCartID);

            //load up the includes
            query = query.Include(ci => ci.PricingOption);
            query = query.Include(ci=>ci.Product);

            return query.ToList();
        }

        public IEnumerable<StoreCart> GetCart(string shoppingCartID)
        {
            var query = _repository.ListStoreCartItems().AsQueryable();

            query = query.Where(p => p.CartID == shoppingCartID);

            query = query.Include(ci => ci.PricingOption);

            return query.ToList();
        }

        public IEnumerable<StoreOrder> ListOrders(Guid userId)
        {
            var query = _repository.ListOrders().AsQueryable();

            query = query.Where(p => p.UserID == userId);
            
            query = query.Include(o => o.OrderDetails.Select(od => od.PriceOption));
            query = query.Include(o => o.OrderDetails.Select(od => od.Product));
            query = query.Include(o => o.ShippingMethodRate.ShippingMethod);  

            return query.ToList();
        }

        public IEnumerable<StoreShippingMethodRate> ListShippingMethodRates(int portalId)
        {
            var query = _repository.ListShippingMethodRates().AsQueryable();

            query = query.Where(p => p.ShippingMethod.PortalID == portalId);

            query = query.Include(o => o.ShippingMethod);

            return query.ToList();
        }

        public IEnumerable<StoreOrder> ListOrders(int portalId, DateTime dateToGetOrdersFor)
        {
            var query = _repository.ListOrders().AsQueryable();

            query = query.Where(p => p.PortalID == portalId);

            query = query.Where(r => SqlFunctions.DatePart("day", r.OrderDate) == dateToGetOrdersFor.Day);
            query = query.Where(r => SqlFunctions.DatePart("month", r.OrderDate) == dateToGetOrdersFor.Month);

            query = query.Include(o => o.OrderDetails.Select(od => od.PriceOption));
            query = query.Include(o => o.OrderDetails.Select(od => od.Product));
            query = query.Include(o => o.ShippingMethodRate.ShippingMethod);  

            return query.ToList();
        }

        public StoreOrder GetOrder(int orderId, Guid userId)
        {
            var query = _repository.ListOrders().AsQueryable();

            query = query.Where(p => p.OrderID==orderId);
            query = query.Where(p => p.UserID == userId);

            query = query.Include(o => o.OrderDetails.Select(od => od.PriceOption));
            query = query.Include(o => o.OrderDetails.Select(od => od.Product));
            query = query.Include(o => o.ShippingMethodRate.ShippingMethod);  

            return query.FirstOrDefault();
        }

        public StoreOrder GetOrder(Guid userId)
        {
            var query = _repository.ListOrders().AsQueryable();

            query = query.Where(p => p.UserID == userId);

            query = query.Include(o => o.OrderDetails.Select(od => od.PriceOption));
            query = query.Include(o => o.OrderDetails.Select(od => od.Product));
            query = query.Include(o => o.ShippingMethodRate.ShippingMethod);  

            query = query.OrderByDescending(o => o.OrderID);

            return query.FirstOrDefault();
        }

        public StoreCart GetCart(int recordId)
        {
            var query = _repository.ListStoreCartItems().AsQueryable();

            query = query.Where(p => p.RecordID == recordId);

            query = query.Include(p => p.Product);

            return query.FirstOrDefault();
        }

        public StorePricingOption GetPriceOption(int priceOptionId)
        {
            var query = _repository.ListPriceOptions().AsQueryable();

            query = query.Where(p => p.PriceOptionID == priceOptionId);

            return query.FirstOrDefault();
        }

        public StoreShippingMethodRate GetShippingMethodRate(int shippingRateId)
        {
            var query = _repository.ListShippingMethodRates().AsQueryable();

            query = query.Where(p => p.ShippingRateID == shippingRateId);

            query = query.Include(o => o.ShippingMethod);  

            return query.FirstOrDefault();
        }

        public StoreProduct GetProduct(int productId)
        {
            var query = _repository.ListProducts().AsQueryable();

            query = query.Where(p => p.ProductID == productId);

            query = query.Include(c => c.Category);
            query = query.Include(c => c.PricingOptions);

            return query.FirstOrDefault();
        }

        public StoreCategory GetCategory(string category, int portalId)
        {
            var query = _repository.ListCategories().AsQueryable();

            query = query.Where(p => p.PortalID == portalId);
            query = query.Where(p => p.Name == category);

            query = query.Include(c => c.Products);

            return query.FirstOrDefault();
        }

        public IEnumerable<StoreProduct> ListTopSellingActiveProducts(int portalId, int count)
        {
            var query = _repository.ListProducts().AsQueryable();

            query = query.Where(c => c.Active);
            query = query.Where(p => p.Category.PortalID == portalId);

            query = query.OrderByDescending(a => a.OrderDetails.Count());
            query = query.Take(count);

            return query.ToList();
        }

        public IEnumerable<StorePricingOption> ListPriceOptions(int portalId)
        {
            var query = _repository.ListPriceOptions().AsQueryable();

            query = query.Where(p => p.PortalID == portalId);

            return query.ToList();
        }

        public IEnumerable<StoreCategory> ListCategories(int portalId)
        {
            var query = _repository.ListCategories().AsQueryable();
            
            query = query.Where(p => p.PortalID == portalId);

            return query.ToList();
        }

        public IEnumerable<StoreProduct> ListActiveProducts(int portalId)
        {
            var query = _repository.ListProducts().AsQueryable();

            query = query.Where(c => c.Active);
            query = query.Where(p => p.PortalID == portalId);

            return query.ToList();
        }

        public IEnumerable<StoreProduct> ListActiveProductsWithCategory(int portalId)
        {
            var query = _repository.ListProducts().AsQueryable();

            query = query.Where(c => c.Active);
            query = query.Where(p => p.PortalID == portalId);

            //load up the includes
            query = query.Include(c => c.Category);

            return query.ToList();
        }

        public bool EditPriceOption(StorePricingOption priceOptionToEdit)
        {
            try
            {
                _repository.EditPriceOption(priceOptionToEdit);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }

        public bool EditProduct(StoreProduct productToEdit)
        {
            try
            {
                _repository.EditProduct(productToEdit);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }

        public bool EditCartItem(StoreCart cartToEdit)
        {
            try
            {
                _repository.EditCart(cartToEdit);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }

        public bool DeleteCartItem(StoreCart cartToEdit)
        {
            try
            {
                _repository.DeleteCart(cartToEdit);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }

        public bool CreateCart(StoreCart cartToCreate)
        {
            try
            {
                _repository.CreateCart(cartToCreate);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }
    }
}
